package com.vzoom.logdesensitization;


import com.vzoom.logdesensitization.config.DesensitizationStrategyHolder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class AtStringTemplate implements InitializingBean {

    private static Map<String, DesensitizationStrategy> strategyMap;

    @Autowired
    private DesensitizationStrategyHolder desensitizationStrategyHolder;

    public static String render(String template, Object[] arr) {
        int forwardIndex = 0;
        int arrCurrentIndex = 0;
        int arrIndex = arr.length - 1;
        int backIndex;
        int templateLength = template.length();
        int appendIndexStart = 0;
        int appendIndexEnd;
        char c0, c1;
        char ca, cb;
        boolean findAt;
        StringBuilder renderSb = new StringBuilder();
        StringBuilder atSb = new StringBuilder();
        String strategyName = null;
        while (forwardIndex < templateLength) {
            c0 = template.charAt(forwardIndex++);
            if (c0 == '{') {
                c1 = template.charAt(forwardIndex++);
                if (c1 == '}') {
                    backIndex = forwardIndex - 3;
                    appendIndexEnd = backIndex + 1;
                    if (arrCurrentIndex <= arrIndex) {
                        findAt = false;
                        atSb.delete(0, atSb.length());
                        while (backIndex >= 0) {
                            ca = template.charAt(backIndex--);
                            if (ca == '}') {
                                cb = template.charAt(backIndex--);
                                if (cb == '{') {
                                    break;
                                }
                            }
                            if (ca == '@') {
                                strategyName = atSb.reverse().toString();
                                if (strategyMap.containsKey(strategyName)) {
                                    appendIndexEnd = backIndex + 1;
                                    findAt = true;
                                }
                                break;
                            } else {
                                if (Character.isWhitespace(ca)) {
                                    break;
                                } else {
                                    atSb.append(ca);
                                }
                            }
                        }
                        renderSb.append(template, appendIndexStart, appendIndexEnd);
                        if (findAt) {
                            DesensitizationStrategy desensitizationStrategy = strategyMap.get(strategyName);
                            renderSb.append(desensitizationStrategy.desensitization(arr[arrCurrentIndex]));
                        } else {
                            renderSb.append(arr[arrCurrentIndex]);
                        }
                        appendIndexStart = forwardIndex;
                    }
                    arrCurrentIndex++;
                    if (arrCurrentIndex > arrIndex) {
                        break;
                    }
                }
            }
        }
        if (appendIndexStart < templateLength) {
            renderSb.append(template, appendIndexStart, templateLength);
        }
        return renderSb.toString();
    }

    public static String renderObject(String template, Object[] arr, int[] indices) {
        int forwardIndex = 0;
        int arrCurrentIndex = 0;
        int arrIndex = arr.length - 1;
        int backIndex;
        int templateLength = template.length();
        int appendIndexStart = 0;
        int appendIndexEnd;
        char c0, c1;
        char ca, cb;
        boolean findAt;
        StringBuilder renderSb = new StringBuilder();
        StringBuilder atSb = new StringBuilder();
        String strategyName = null;
        while (forwardIndex < templateLength) {
            c0 = template.charAt(forwardIndex++);
            if (c0 == '{') {
                c1 = template.charAt(forwardIndex++);
                if (c1 == '}') {
                    backIndex = forwardIndex - 3;
                    appendIndexEnd = backIndex + 1;
                    if (arrCurrentIndex <= arrIndex) {
                        findAt = false;
                        atSb.delete(0, atSb.length());
                        while (backIndex >= 0) {
                            ca = template.charAt(backIndex--);
                            if (ca == '}') {
                                cb = template.charAt(backIndex--);
                                if (cb == '{') {
                                    break;
                                }
                            }
                            if (ca == '@') {
                                strategyName = atSb.reverse().toString();
                                if (strategyMap.containsKey(strategyName)) {
                                    appendIndexEnd = backIndex + 1;
                                    findAt = true;
                                }
                                break;
                            } else {
                                if (Character.isWhitespace(ca)) {
                                    break;
                                } else {
                                    atSb.append(ca);
                                }
                            }
                        }
                        renderSb.append(template, appendIndexStart, appendIndexEnd);
                        if (findAt) {
                            DesensitizationStrategy desensitizationStrategy = strategyMap.get(strategyName);
                            arr[arrCurrentIndex] = desensitizationStrategy.desensitization(arr[arrCurrentIndex]);
                        }
                        appendIndexStart = forwardIndex;
                    }
                    renderSb.append("{}");
                    arrCurrentIndex++;
                    if (arrCurrentIndex > arrIndex) {
                        break;
                    }
                }
            }
        }
        if (appendIndexStart < templateLength) {
            renderSb.append(template, appendIndexStart, templateLength);
        }
        String messagePattern = renderSb.toString();
        templateLength = messagePattern.length();
        forwardIndex = 0;
        arrCurrentIndex = 0;
        while (forwardIndex < templateLength) {
            c0 = messagePattern.charAt(forwardIndex++);
            if (c0 == '{') {
                c1 = messagePattern.charAt(forwardIndex++);
                if (c1 == '}') {
                    indices[arrCurrentIndex] = forwardIndex - 2;
                }
            }
        }
        return messagePattern;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        strategyMap = desensitizationStrategyHolder.getStrategyMap();
    }
}
